"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

import sys
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import Permission
from django.db.models import Max, Q

from siriuso.models.postgres import CallableEncoder
from siriuso.utils import default_lingvo, get_enhavo, perms
from universo_bazo.models import UniversoBazaMaks, UniversoBazaRealeco, Realeco
from objektoj.models import Objekto
from main.models import Uzanto


# Категории навыков, использует абстрактный класс UniversoBazaMaks
class ScipovoKategorio(UniversoBazaMaks):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор (пользователь, который создал сущность или для которого создана сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # название, многоязычное в JSON формате
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание, многоязычное в JSON формате
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # параллельный мир в котором есть эта сущность, может быть в нескольких
    realeco = models.ManyToManyField(Realeco, verbose_name=_('Realeco'),
                                     db_table='scipovoj_kategorioj_realeco_ligiloj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'scipovoj_kategorioj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Kategorio de scipovoj')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Kategorioj de scipovoj')
        # права
        permissions = (
            ('povas_vidi_scipovoj_kategorioj', _('Povas vidi kategorioj de scipovoj')),
            ('povas_krei_scipovoj_kategorioj', _('Povas krei kategorioj de scipovoj')),
            ('povas_forigi_scipovoj_kategorioj', _('Povas forigu kategorioj de scipovoj')),
            ('povas_shanghi_scipovoj_kategorioj', _('Povas ŝanĝi kategorioj de scipovoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле nomo этой модели
        return '{}) {}'.format(self.id, get_enhavo(self.nomo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id += 1
            super(model, self).__setattr__('id', next_id)

        super(ScipovoKategorio, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                                   update_fields=update_fields)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('scipovoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'scipovoj.povas_vidi_scipovoj_kategorioj',
                'scipovoj.povas_krei_scipovoj_kategorioj',
                'scipovoj.povas_forigi_scipovoj_kategorioj',
                'scipovoj.povas_shanghi_scipovoj_kategorioj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='scipovoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('scipovoj.povas_vidi_scipovoj_kategorioj')
                    or user_obj.has_perm('scipovoj.povas_vidi_scipovoj_kategorioj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('scipovoj.povas_vidi_scipovoj_kategorioj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond


# Типы навыков, использует абстрактный класс UniversoBazaMaks
class ScipovoTipo(UniversoBazaMaks):

    # ID записи
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор (пользователь, который создал сущность или для которого создана сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # название, многоязычное в JSON формате
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание, многоязычное в JSON формате
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # параллельный мир в котором есть эта сущность, может быть в нескольких
    realeco = models.ManyToManyField(Realeco, verbose_name=_('Realeco'),
                                     db_table='scipovoj_tipoj_realeco_ligiloj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'scipovoj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de scipovoj')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de scipovoj')
        # права
        permissions = (
            ('povas_vidi_scipovoj_tipoj', _('Povas vidi tipoj de scipovoj')),
            ('povas_krei_scipovoj_tipoj', _('Povas krei tipoj de scipovoj')),
            ('povas_forigi_scipovoj_tipoj', _('Povas forigu tipoj de scipovoj')),
            ('povas_shanghi_scipovoj_tipoj', _('Povas ŝanĝi tipoj de scipovoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле nomo этой модели
        return '{}) {}'.format(self.id, get_enhavo(self.nomo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id += 1
            super(model, self).__setattr__('id', next_id)

        super(ScipovoTipo, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                              update_fields=update_fields)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('scipovoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'scipovoj.povas_vidi_scipovoj_tipoj',
                'scipovoj.povas_krei_scipovoj_tipoj',
                'scipovoj.povas_forigi_scipovoj_tipoj',
                'scipovoj.povas_shanghi_scipovoj_tipoj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='scipovoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('scipovoj.povas_vidi_scipovoj_tipoj')
                    or user_obj.has_perm('scipovoj.povas_vidi_scipovoj_tipoj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('scipovoj.povas_vidi_scipovoj_tipoj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond


# Уровни навыков, использует абстрактный класс UniversoBazaMaks
class ScipovoNivelo(UniversoBazaMaks):

    # автор (пользователь, который создал сущность или для которого создана сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # значение уровня
    nivelo = models.IntegerField(_('Nivelo'), unique=True, default=0)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'scipovoj_niveloj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Nivelo de scipovoj')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Niveloj de scipovoj')
        # права
        permissions = (
            ('povas_vidi_scipovoj_niveloj', _('Povas vidi nivelo de scipovoj')),
            ('povas_krei_scipovoj_niveloj', _('Povas krei nivelo de scipovoj')),
            ('povas_forigi_scipovoj_niveloj', _('Povas forigu nivelo de scipovoj')),
            ('povas_shanghi_scipovoj_niveloj', _('Povas ŝanĝi nivelo de scipovoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле nivelo этой модели
        return '{}'.format(self.nivelo)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('scipovoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'scipovoj.povas_vidi_scipovoj_niveloj',
                'scipovoj.povas_krei_scipovoj_nivelo',
                'scipovoj.povas_forigi_scipovoj_niveloj',
                'scipovoj.povas_shanghi_scipovoj_niveloj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='scipovoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('scipovoj.povas_vidi_scipovoj_niveloj')
                    or user_obj.has_perm('scipovoj.povas_vidi_scipovoj_niveloj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('scipovoj.povas_vidi_scipovoj_niveloj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond


# Справочник навыков, использует абстрактный класс UniversoBazaMaks
class Scipovo(UniversoBazaMaks):

    # ID записи
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор (пользователь, который создал сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # категория навыков
    kategorio = models.ManyToManyField(ScipovoKategorio, verbose_name=_('Kategorio'),
                                       db_table='scipovoj_kategorioj_ligiloj')

    # тип навыков
    tipo = models.ForeignKey(ScipovoTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # название, многоязычное в JSON формате
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание, многоязычное в JSON формате
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # параллельный мир в котором есть эта сущность, может быть в нескольких
    realeco = models.ManyToManyField(Realeco, verbose_name=_('Realeco'),
                                     db_table='scipovoj_realeco_ligiloj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'scipovoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Scipovo')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Scipovoj')
        # права
        permissions = (
            ('povas_vidi_scipovoj', _('Povas vidi scipovoj')),
            ('povas_krei_scipovoj', _('Povas krei scipovoj')),
            ('povas_forigi_scipovoj', _('Povas forigu scipovoj')),
            ('povas_shanghi_scipovoj', _('Povas ŝanĝi scipovoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле nomo этой модели
        return '{}'.format(get_enhavo(self.nomo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id += 1
            super(model, self).__setattr__('id', next_id)

        super(Scipovo, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                              update_fields=update_fields)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('scipovoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'scipovoj.povas_vidi_scipovoj',
                'scipovoj.povas_krei_scipovoj',
                'scipovoj.povas_forigi_scipovoj',
                'scipovoj.povas_shanghi_scipovoj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='scipovoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('scipovoj.povas_vidi_scipovoj')
                    or user_obj.has_perm('scipovoj.povas_vidi_scipovoj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('scipovoj.povas_vidi_scipovoj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond


# Навыки объектов, касается роботов-аватаров и не только, использует абстрактный класс UniversoBazaRealeco
class ScipovoObjekto(UniversoBazaRealeco):

    # объект
    objekto = models.ForeignKey(Objekto, verbose_name=_('Objekto'), blank=False, default=None,
                                on_delete=models.CASCADE)

    # навык
    scipovo = models.ForeignKey(Scipovo, verbose_name=_('Scipovo'), blank=False, default=None,
                                on_delete=models.CASCADE)

    # уровень навыка
    nivelo = models.ForeignKey(ScipovoNivelo, verbose_name=_('Nivelo'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'scipovoj_objekto'
        # читабельное название модели, в единственном числе
        verbose_name = _('Scipovo de objektoj')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Scipovoj de objektoj')
        # права
        permissions = (
            ('povas_vidi_scipovoj_objektoj', _('Povas vidi scipovoj de objektoj')),
            ('povas_krei_scipovoj_objektoj', _('Povas krei scipovoj de objektoj')),
            ('povas_forigi_scipovoj_objektoj', _('Povas forigu scipovoj de objektoj')),
            ('povas_shanghi_scipovoj_objektoj', _('Povas ŝanĝi scipovoj de objektoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле objekto этой модели
        return '{}'.format(self.objekto)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('scipovoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'scipovoj.povas_vidi_scipovoj_objektoj',
                'scipovoj.povas_krei_scipovoj_objektoj',
                'scipovoj.povas_forigi_scipovoj_objektoj',
                'scipovoj.povas_shanghi_scipovoj_objektoj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='scipovoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('scipovoj.povas_vidi_scipovoj_objektoj')
                    or user_obj.has_perm('scipovoj.povas_vidi_scipovoj_objektoj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('scipovoj.povas_vidi_scipovoj_objektoj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond
